<template>
	<view class="tui-skeleton-common tui-skeleton-box" :style="{ width: winWidth + 'px', height: winHeight + 'px', backgroundColor: backgroundColor }">
		<view
			class="tui-skeleton-common"
			v-for="(item, index) in skeletonElements"
			:key="index"
			:style="{
				width: item.width + 'px',
				height: item.height + 'px',
				left: item.left + 'px',
				top: item.top + 'px',
				backgroundColor: skeletonBgColor,
				borderRadius: getRadius(item.skeletonType, borderRadius)
			}"
		></view>

		<view class="tui-loading" :class="[getLoadingType(loadingType)]" v-if="isLoading"></view>
	</view>
</template>

<script setup>
import { ref, reactive, toRefs, watch, onBeforeMount, onMounted } from 'vue'

const emit = defineEmits(['click'])

const props = defineProps({
	//选择器(外层容器)
	selector: {
		type: String,
		default: 'tui-skeleton'
	},
	//外层容器背景颜色
	backgroundColor: {
		type: String,
		default: '#fff'
	},
	//骨架元素背景颜色
	skeletonBgColor: {
		type: String,
		default: '#e9e9e9'
	},
	//骨架元素类型：矩形，圆形，带圆角矩形["rect","circular","fillet"]
	//默认所有，根据页面情况进行传值
	//页面对应元素class为：tui-skeleton-rect，tui-skeleton-circular，tui-skeleton-fillet
	//如果传入的值不在下列数组中，则为自定义class值，默认按矩形渲染
	skeletonType: {
		type: Array,
		default() {
			return ['rect', 'circular', 'fillet']
		}
	},
	//圆角值，skeletonType=fillet时生效
	borderRadius: {
		type: String,
		default: '16rpx'
	},
	//骨架屏预生成数据：提前生成好的数据，当传入该属性值时，则不会再次查找子节点信息
	preloadData: {
		type: Array,
		default() {
			return []
		}
	},
	//是否需要loading
	isLoading: {
		type: Boolean,
		default: true
	},
	//loading类型[1-10]
	loadingType: {
		type: Number,
		default: 1
	}
})

const state = reactive({
	winWidth: 375,
	winHeight: 800,
	skeletonElements: []
})

onBeforeMount(() => {
	const { windowWidth, windowHeight } = uni.getSystemInfoSync()
	state.winWidth = windowWidth
	state.winHeight = windowHeight
	//如果有预生成数据，则直接使用
	isPreload(true)
})

onMounted(() => {
	nextTick(() => {
		nodesRef(`.${props.selector}`).then(res => {
			if (res && res[0]) {
				state.winHeight = res[0].height + Math.abs(res[0].top)
			}
		})
		!isPreload() && selectorQuery()
	})
})

const getLoadingType = type => {
	let value = 1
	if (type && type > 0 && type < 11) {
		value = type
	}
	return 'tui-loading-' + value
}

const getRadius = (type, val) => {
	let radius = '0'
	if (type == 'circular') {
		radius = '50%'
	} else if (type == 'fillet') {
		radius = val
	}
	return radius
}

const isPreload = init => {
	let preloadData = props.preloadData || []
	if (preloadData.length) {
		init && (state.skeletonElements = preloadData)
		return true
	}
	return false
}

const selectorQuery = async () => {
	let skeletonType = props.skeletonType || []
	let nodes = []
	for (let item of skeletonType) {
		let className = ''

		// #ifndef MP-WEIXIN
		className = `.${item}`
		if (~'rect_circular_fillet'.indexOf(item)) {
			className = `.${props.selector}-${item}`
		}
		// #endif

		// #ifdef MP-WEIXIN
		className = `.${props.selector} >>> .${item}`
		if (~'rect_circular_fillet'.indexOf(item)) {
			className = `.${props.selector} >>> .${props.selector}-${item}`
		}
		// #endif

		await nodesRef(className).then(res => {
			res.map(d => {
				d.skeletonType = item
			})
			nodes = nodes.concat(res)
		})
	}
	state.skeletonElements = [...nodes]
}

const nodesRef = async className => {
	return await new Promise((resolve, reject) => {
		uni.createSelectorQuery()
			.selectAll(className)
			.boundingClientRect()
			.exec(res => {
				if (res) {
					resolve(res)
				} else {
					reject(res)
				}
			})
	})
}

const { winWidth, winHeight, skeletonElements } = toRefs(state)
</script>

<style lang="scss" scoped>
.tui-skeleton-common {
	position: absolute;
	z-index: 99999;
}

.tui-skeleton-box {
	left: 0;
	top: 0;
}

.tui-loading {
	display: inline-block;
	vertical-align: middle;
	width: 40rpx;
	height: 40rpx;
	background: 0 0;
	border-radius: 50%;
	border: 2px solid;
	animation: tui-rotate 0.7s linear infinite;
	position: fixed;
	z-index: 999999;
	left: 50%;
	top: 50%;
	margin-left: -20rpx;
	margin-top: -20rpx;
}

.tui-loading-1 {
	border-color: #e5e5e5 #e5e5e5 #e5e5e5 #5677fc;
}

.tui-loading-2 {
	border-color: #e5e5e5 #e5e5e5 #e5e5e5 #8f8d8e;
}

.tui-loading-3 {
	border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) #fff;
}

.tui-loading-4 {
	border-color: #e5e5e5 #e5e5e5 #e5e5e5 #35b06a;
}

.tui-loading-5 {
	border-color: #e5e5e5 #e5e5e5 #e5e5e5 #fc872d;
}

.tui-loading-6 {
	border-color: #e5e5e5 #e5e5e5 #e5e5e5 #eb0909;
}

.tui-loading-7 {
	border-color: #5677fc transparent #5677fc transparent;
}

.tui-loading-8 {
	border-color: #35b06a transparent #35b06a transparent;
}

.tui-loading-9 {
	border-color: #fc872d transparent #fc872d transparent;
}

.tui-loading-10 {
	border-color: #eb0909 transparent #eb0909 transparent;
}

@-webkit-keyframes tui-rotate {
	0% {
		transform: rotate(0);
	}

	100% {
		transform: rotate(360deg);
	}
}

@keyframes tui-rotate {
	0% {
		transform: rotate(0);
	}

	100% {
		transform: rotate(360deg);
	}
}
</style>
